package rekursion;

import javax.swing.JComponent;
import javax.swing.JFrame;
import java.util.Stack;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Dimension;
import java.awt.geom.Rectangle2D;
import java.util.Scanner;

class UnerlaubterZugException extends RuntimeException{
  public UnerlaubterZugException(String s){
    super(s);
  }
}

public class HanoiComponent extends JComponent{
  int steine;
  int zuege;
  long warten;
  Stack[] turm=new Stack[3];

  public HanoiComponent(int anz){
    steine=anz;
    for(int i=0; i<3; ++i) turm[i]=new Stack<Integer>();
    reset();
    setMinimumSize(new Dimension(150,50));
  }

  public void verlangsame(long d){warten=d;}

  public void reset(){
    zuege=0;
    for(int i=0; i<3; ++i) turm[i].clear();
    for(int i=steine; i>0; --i) turm[0].push(new Integer(i));
    repaint();
  }

  public void vonNach(int von, int nach){
    if(!okVonNach(von, nach))
      throw new UnerlaubterZugException("von="+von+" nach="+nach);
    turm[nach].push(turm[von].pop());
    repaint();
    zuege++;
    if(warten>0)
      try{Thread.sleep(warten);} catch(Exception ex){}
  }

  public int zuege(){return zuege;}

  public boolean fertig(){
    return turm[1].size()==steine || turm[2].size()==steine;
  }

  public boolean okVonNach(int von, int nach){
    if(von<0 || von>2 || nach<0 || nach>2) return false;
    if(turm[von].empty()) return false;
    if(turm[nach].empty()) return true;
    return ((Integer)turm[von].peek()).compareTo((Integer)turm[nach].peek())<0;
  }

  private Dimension size=new Dimension();
  private Rectangle2D rect=new Rectangle2D.Double();
  @Override
  public void paintComponent(Graphics g){
    Graphics2D g2=(Graphics2D)g;
    size=getSize(size);
    rect.setRect(0,0,size.width,size.height);
    g2.setColor(Color.white);
    g2.fill(rect);
    g2.setColor(Color.gray);
    double dx=10;
    //Höhe und Breite des größten Steins
    double breit=(size.getWidth()-2*dx)/3;// --- 10 --- 10 ---
    double hoch=size.getHeight()*1.0/steine;
    for(int i=0; i<3; ++i){// zeichne die drei T�rme
      for(int j=0, h=turm[i].size(); j<h; ++j){
        double w=(breit/steine)*((Integer)turm[i].get(j)).intValue();
        rect.setRect(i*(breit+dx)+(breit-w)/2, (steine-j-1)*hoch, w, hoch);
        g2.draw(rect);
      }
    }
  }

//====== ab hier groöe Schweinerei für praktischen Einsatz im Unterricht ======
  private static HanoiComponent hanoicomp;
  public static void main(String[] args){
    Scanner eingabe=new Scanner(System.in);
    //Erzeuge ein Fenster, das die HanoiComponent beinhaltet
    JFrame f=new JFrame();
    if(args.length<1){
      System.out.println("java HanoiComponent <turmhöhe> [selber]");
      System.exit(1);
    }
    int h=Integer.parseInt(args[0]);
    hanoicomp=new HanoiComponent(h);
    hanoicomp.verlangsame(300);
    f.getContentPane().add(hanoicomp);
    f.setBounds(0,0,200,100);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
    if(args.length>1 && args[1].equals("selber")){
      //hole zweistellige Zahlen vom Benutzer (1=links, 2=Mitte, 3=rechts)
      while(!hanoicomp.fertig()){
        int zug=eingabe.nextInt()-11;
        int von=zug/10, nach=zug%10;
        if(hanoicomp.okVonNach(von,nach)) hanoicomp.vonNach(von,nach);
        else System.out.println("Unerlaubter Zug.");
      }
    } else bewege(h, 0, 2);
    System.out.println("Geschafft in "+hanoicomp.zuege()+" Zügen.");
  }
  
  public static void bewege(int hoch, int von, int nach){
    if(hoch>0){
      int hilf=3-von-nach;
      bewege(hoch-1, von, hilf);
      hanoicomp.vonNach(von, nach);
      bewege(hoch-1, hilf, nach);
    }
  }
}
